package com.example.flowable.controller;

import java.util.*;

import com.example.flowable.model.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.IdentityService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.validation.ProcessValidator;
import org.flowable.validation.ProcessValidatorFactory;
import org.flowable.validation.ValidationError;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "dynamic")
@Slf4j
public class DynamicController {
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private IdentityService identityService;

    @RequestMapping(value = "deploy")
    @ResponseBody
    public String deploy() {
        //部署流程
//        SequenceFlow flow1 = new SequenceFlow();
//        flow1.setId("flow1");
//        flow1.setName("开始节点->任务节点1");
//        flow1.setSourceRef("start1");
//        flow1.setTargetRef("userTask1");
//        // 任务节点1->任务节点2
//        SequenceFlow flow2 = new SequenceFlow();
//        flow2.setId("flow2");
//        flow2.setName("任务节点1->任务节点2");
//        flow2.setSourceRef("userTask1");
//        flow2.setTargetRef("userTask2");
//
//        // 任务节点1->任务节点2
//        SequenceFlow flow3 = new SequenceFlow();
//        flow3.setId("flow3");
//        flow3.setName("任务节点2->结束节点");
//        flow3.setSourceRef("userTask2");
//        flow3.setTargetRef("endEvent");
//
//        // 声明BpmnModel对象
//        BpmnModel bpmnModel = new BpmnModel();
//        // 声明Process对象 一个BpmnModel可以包含多个Process对象
//        Process process = new Process();
//        process.setId("dynamicKey");
//        process.setName("dynamicName");
//        // 开始节点的封装
//        StartEvent start = new StartEvent();
//        start.setName("开始节点");
//        start.setId("start1");
//        start.setOutgoingFlows(Arrays.asList(flow1));
//        // 任务节点1
//        UserTask userTask1 = new UserTask();
//        userTask1.setName("任务节点1");
//        userTask1.setId("userTask1");
//        userTask1.setIncomingFlows(Arrays.asList(flow1));
//        userTask1.setOutgoingFlows(Arrays.asList(flow2));
//        // 任务节点2
//        UserTask userTask2 = new UserTask();
//        userTask2.setName("任务节点2");
//        userTask2.setId("userTask2");
//        userTask2.setIncomingFlows(Arrays.asList(flow2));
//        userTask2.setOutgoingFlows(Arrays.asList(flow3));
//
//        // 结束节点
//        EndEvent endEvent = new EndEvent();
//        endEvent.setName("结束节点");
//        endEvent.setId("endEvent");
//        endEvent.setIncomingFlows(Arrays.asList(flow3));
//        // 将所有的FlowElement添加到process中
//        process.addFlowElement(start);
//        process.addFlowElement(flow1);
//        process.addFlowElement(userTask1);
//        process.addFlowElement(flow2);
//        process.addFlowElement(userTask2);
//        process.addFlowElement(flow3);
//        process.addFlowElement(endEvent);
//        bpmnModel.addProcess(process);

//        Deployment deployment = processEngine.getRepositoryService().createDeployment().addBpmnModel("dynamic.bpmn", bpmnModel)
//                .deploy();



        Map<String, String> map = new HashMap<>();
        map.put("procinstId", "procinstId");
        map.put("procinstName", "procinstName");
        map.put("procinstType", "procinstType");
        map.put("procinstTypeName", "procinstTypeName");
        createFlowableBpmn(map);

//        return "部署成功.流程Id为：" + deployment.getId();
        return null;
    }

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("procinstId", "procinstId");
        map.put("procinstName", "procinstName");
        map.put("procinstType", "procinstType");
        map.put("procinstTypeName", "procinstTypeName");

//        createFlowableBpmn(map);
    }

    /**
     * 根据流程信息和节点配置创建流程图
     * 传入map
     *
     * @return
     */
    public void createFlowableBpmn(Map<String, String> map) {
        //流程名称、流程id，流程类型、
        if (null == map.get("procinstId")|| StringUtils.isBlank(map.get("procinstName")) || StringUtils.isBlank(map.get("procinstTypeName")) || StringUtils.isBlank(map.get("procinstType"))) {
            throw new RuntimeException("procinstId、procinstName、procinstTypeName、ProcinstType不允许为空");
        }
        //数据校验：传入的数据节点字段：流程配置id、节点id、节点顺序、节点描述
//        List<MgProcinstNode> nodeList = map.get("procinstNode");
//        if (ListUtil.isEmpty(nodeList) || nodeList.size() < MIN_NODE_SIZE) {
//            throw new RuntimeException("流程节点不能少于两个，请配置发起人节点和至少一个审批节点");
//        }
        //流程配置节点主键id过滤
//        List<Long> ids = nodeList.stream().map(MgProcinstNode::getProcinstNodeId).distinct().filter(Objects::nonNull).collect(Collectors.toList());
//        if (ListUtil.isEmpty(ids) || ids.size() < nodeList.size()){
//            throw new RuntimeException("请检查node节点的主键id是否为空");
//        }
        /*
         * 整合节点和连线成为一个 process
         */
        Process process = new Process();
        // 流程标识
        process.setId("pro_" + map.get("procinstId"));
        process.setName(map.get("procinstName"));


        //开始事件
        FlowElement startEvent = createStartFlowElement("start","开始");
        process.addFlowElement(startEvent);
        //结束事件--任务正常完成
        FlowElement completeEvent = createEndFlowElement("complete","结束");

        List<UserTask> userTaskList = createCommonUserTask(/*nodeList*/);
        //发起人节点
        UserTask startUserTask = userTaskList.get(0);
        for (int i = 0; i < userTaskList.size(); i++) {
            UserTask userTask = userTaskList.get(i);
            process.addFlowElement(userTask);
            //发起人到第一个节点不需要网关
            if(i == 0) {
                // 开始节点到发起人节点
                SequenceFlow startSequenceFlow = new SequenceFlow(startEvent.getId(), userTask.getId());
                process.addFlowElement(startSequenceFlow);

                // 发起人节点到审批节点

                UserTask nextUserTask = userTaskList.get(i + 1);
                SequenceFlow sequenceFlow = new SequenceFlow(userTask.getId(), nextUserTask.getId());
                process.addFlowElement(sequenceFlow);
            } else {
                //从发起人后的第一个节点开始增加网关节点
                ExclusiveGateway exclusiveGateway = createGateway(i,userTask.getName());
                process.addFlowElement(exclusiveGateway);
                //审批节点到网关节点
                SequenceFlow sequenceFlow = new SequenceFlow(userTask.getId(), exclusiveGateway.getId());
                sequenceFlow.setName(userTask.getName()+ "开始审批");
                process.addFlowElement(sequenceFlow);
                // 取下一步的节点id，可能为结束节点或者审批节点
                String nextUserTaskId = completeEvent.getId();
                if (userTaskList.size() - i > 1 ){
                    nextUserTaskId = userTaskList.get(i + 1).getId();
                }
                //网关节点审批通过继续下一步
                SequenceFlow sequenceFlowAgree = new SequenceFlow(exclusiveGateway.getId(), nextUserTaskId);
                sequenceFlowAgree.setConditionExpression("${agree == 1}");
                sequenceFlowAgree.setName("同意");
                process.addFlowElement(sequenceFlowAgree);
                //网关节点审批拒绝返回到发起人,认领直接终止流程
                SequenceFlow sequenceFlowRefuse = new SequenceFlow(exclusiveGateway.getId(),startUserTask.getId());
                sequenceFlowRefuse.setConditionExpression("${agree == 0}");
                sequenceFlowRefuse.setName("拒绝");
                process.addFlowElement(sequenceFlowRefuse);
            }
        }

        process.addFlowElement(completeEvent);


        BpmnModel bpmnModel = new BpmnModel();
        bpmnModel.addProcess(process);
        // 自动生成布局 布局节点位置
//        new BpmnAutoLayout(bpmnModel).execute();

        BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
        byte[] convertToXML = bpmnXMLConverter.convertToXML(bpmnModel);
        String bytes = new String(convertToXML);
        log.info("该流程的流程xml为：{}", bytes);

        ProcessValidatorFactory processValidatorFactory = new ProcessValidatorFactory();
        ProcessValidator defaultProcessValidator = processValidatorFactory.createDefaultProcessValidator();
        // 验证失败信息的封装ValidationError
        List<ValidationError> validate = defaultProcessValidator.validate(bpmnModel);
        log.error("获取到的验证信息为：{}", validate);
//        if (ListUtil.isNotEmpty(validate) ){
//            throw new RuntimeException("流程有误，请检查后重试");
//        }

        //  流程部署
        Deployment deploy = repositoryService.createDeployment()
//                .tenantId("1099")
                .addString(map.get("procinstName")+".bpmn", bytes)
                .category(map.get("procinstTypeName")).deploy();
        log.info("部署id:" + deploy.getId());
    }

    /**
     * 创建开始节点信息
     * @return
     */
    public static FlowElement createStartFlowElement(String id, String name){
        StartEvent startEvent = new StartEvent();
        startEvent.setId(id);
        startEvent.setName(name);
        startEvent.setInitiator("initiator");
        return startEvent;
    }

    /**
     * 创建结束节点信息
     * @param id
     * @param name
     * @return
     */
    public static FlowElement createEndFlowElement(String id, String name){
        EndEvent endEvent=new EndEvent();
        endEvent.setId(id);
        endEvent.setName(name);
        return endEvent;
    }
    /**
     * 创建普通任务节点信息
     * @param userList 节点信息
     * @return
     */
    public static List<UserTask> createCommonUserTask(){
//        List<MgProcinstNode> nodeList = mgProcinstNodes.stream().sorted((u1, u2) -> u1.getNodeSort().compareTo(u2.getNodeSort())).collect(Collectors.toList());
        List<UserTask> userTaskList = new ArrayList<>();
//        for (int i = 0; i < nodeList.size(); i++) {
//            MgProcinstNode node = nodeList.get(i);
//            UserTask userTask = new UserTask();
//            userTask.setId("task_" + node.getProcinstNodeId());
//            userTask.setName(node.getRoleName());
//            if (i > 0) {
//                userTask.setName(userTask.getName());
//            }else {
//                userTask.setAssignee("${initiator}");
//            }
//            userTaskList.add(userTask);
//        }
        for (int i = 0; i < 3; i++) {
            UserTask userTask = new UserTask();
            userTask.setId("userTaskId" + i);
            userTask.setName("userTaskName" + i);
            userTaskList.add(userTask);
        }
        return userTaskList;
    }

    /**
     * 创建监听类
     * @return
     */
    public List<FlowableListener> CreateTaskListeners(){
        List<FlowableListener> taskListeners = new ArrayList<>();
        FlowableListener listener = new FlowableListener();
        listener.setEvent("all");
        listener.setImplementationType("delegateExpression");
        listener.setImplementation("${permissinTaskListener}");
        //listener.setId("CATEGORYID_FILE_AUDIT_listener");
        taskListeners.add(listener);
        return taskListeners;
    }

    /**
     * 创建拍他网关节点
     * @return
     */
    private static ExclusiveGateway createGateway(Integer i, String name){
        ExclusiveGateway gateway = new ExclusiveGateway();
        gateway.setName(name + "审批");
        gateway.setId("gatewayid" + i);
        return gateway;
    }
}
